﻿<%@ Application Language="C#" %>
<%@ Import Namespace="System" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<%@ Import Namespace="System.Security.Principal" %>
<%@ Import Namespace="System.Threading" %>
<%@ Import Namespace="System.Net" %>
<%@ Import Namespace="System.Diagnostics" %>
<%@ Import Namespace="System.Collections" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.ComponentModel" %>
<%@ Import Namespace="System.Web" %>
<%@ Import Namespace="System.Web.Mail" %>
<%@ Import Namespace="System.Web.Caching" %>
<%@ Import Namespace="System.Web.SessionState" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="PRT" %>
<%@ Import Namespace="System.Messaging" %>

<script runat="server">
    private const string DummyPageUrl = "http://answering/dummy.aspx";
    //private const string DummyPageUrl = "http://localhost:63112/AnsweringService/dummy.aspx";
    private const string CONNECTION_STRING = "Data Source=(local);Initial Catalog=tempdb;Integrated Security=SSPI;";
    private const string LOG_FILE = @"c:\temp\Cachecallback.txt";
    private const string MSMQ_NAME = ".\\private$\\ASPNETService";
    private const string DummyCacheItemKey = "GagaGuguGigi";

    public static ArrayList _JobQueue = new ArrayList();

    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    protected void Application_Start(Object sender, EventArgs e)
    {
        RegisterCacheEntry();

        if (!Roles.RoleExists("Administrator"))
        {
            Roles.CreateRole("Administrator");
        }
        if (!Roles.RoleExists("Operator"))
        {
            Roles.CreateRole("Operator");
        }        
    }

    /// <summary>
    /// Register a cache entry which expires in 1 minute and gives us a callback.
    /// </summary>
    /// <returns></returns>
    private void RegisterCacheEntry()
    {
        // Prevent duplicate key addition
        if (null != HttpContext.Current.Cache[DummyCacheItemKey]) return;

        HttpContext.Current.Cache.Add(DummyCacheItemKey, "Test", null, DateTime.MaxValue,
            TimeSpan.FromMinutes(1), CacheItemPriority.NotRemovable,
            new CacheItemRemovedCallback(CacheItemRemovedCallback));
    }

    /// <summary>
    /// Callback method which gets invoked whenever the cache entry expires.
    /// We can do our "service" works here.
    /// </summary>
    /// <param name="key"></param>
    /// <param name="value"></param>
    /// <param name="reason"></param>
    public void CacheItemRemovedCallback(string key, object value, CacheItemRemovedReason reason)
    {
        Debug.WriteLine("Cache item callback: " + DateTime.Now.ToString());

        // Do the service works
        DoWork();

        // We need to register another cache item which will expire again in one
        // minute. However, as this callback occurs without any HttpContext, we do not
        // have access to HttpContext and thus cannot access the Cache object. The
        // only way we can access HttpContext is when a request is being processed which
        // means a webpage is hit. So, we need to simulate a web page hit and then 
        // add the cache item.
        HitPage();
    }

    /// <summary>
    /// Hits a local webpage in order to add another expiring item in cache
    /// </summary>
    private void HitPage()
    {
        WebClient client = new WebClient();
        client.DownloadData(DummyPageUrl);
    }

    /// <summary>
    /// Asynchronously do the 'service' works
    /// </summary>
    private void DoWork()
    {
        Debug.WriteLine("Begin DoWork...");
        Debug.WriteLine("Running as: " + WindowsIdentity.GetCurrent().Name);

        //DoSomeFileWritingStuff();
        //DoSomeDatabaseOperation();
        //DoSomeEmailSendStuff();
        //DoSomeMSMQStuff();
        //ExecuteQueuedJobs();

        if (Application["OpenCalls"] != null)
        {
            Dictionary<string, OpenCall> openCalls = new Dictionary<string, OpenCall>();
            openCalls = (Dictionary<string, OpenCall>)Application["OpenCalls"];
            foreach (string key in openCalls.Keys)
            {
                if (openCalls[key].TimeStamp.AddMinutes(5) < DateTime.Now)
                {
                    openCalls.Remove(key);
                    Application["OpenCalls"] = openCalls;
                    break;
                }
            }
        }
        Debug.WriteLine("End DoWork...");
    }

    /// <summary>
    /// Execute jobs that are queued for execution at a specific time
    /// </summary>
    private void ExecuteQueuedJobs()
    {
        ArrayList jobs = new ArrayList();

        // Collect which jobs are overdue
        foreach (Job job in _JobQueue)
        {
            if (job.ExecutionTime <= DateTime.Now)
                jobs.Add(job);
        }

        // Eecute the jobs that are overdue
        foreach (Job job in jobs)
        {
            lock (_JobQueue)
            {
                _JobQueue.Remove(job);
            }

            job.Execute();
        }
    }

    /// <summary>
    /// Test file write. Make sure the path allows ASPNET or NETWORK SERVICE account
    /// to write 
    /// </summary>
    private void DoSomeFileWritingStuff()
    {
        Debug.WriteLine("Writing to file...");

        try
        {
            using (StreamWriter writer = new StreamWriter(LOG_FILE, true))
            {
                writer.WriteLine("Cache Callback: {0}", DateTime.Now);
                writer.Close();
            }
        }
        catch (Exception x)
        {
            Debug.WriteLine(x);
        }

        Trace.WriteLine("File write successful");
    }

    /// <summary>
    /// Test database connectivity
    /// </summary>
    private void DoSomeDatabaseOperation()
    {
        Debug.WriteLine("Connecting to database...");

        using (SqlConnection con = new SqlConnection(CONNECTION_STRING))
        {
            con.Open();

            using (SqlCommand cmd = new SqlCommand("INSERT INTO ASPNETServiceLog VALUES (@Message, @DateTime)", con))
            {
                cmd.Parameters.Add("@Message", SqlDbType.VarChar, 1024).Value = "Hi I'm the ASP NET Service";
                cmd.Parameters.Add("@DateTime", SqlDbType.DateTime).Value = DateTime.Now;

                cmd.ExecuteNonQuery();
            }

            con.Close();
        }

        Debug.WriteLine("Database connection successful");
    }

    /// <summary>
    /// Test email send
    /// </summary>
    private void DoSomeEmailSendStuff()
    {
        try
        {
            MailMessage msg = new MailMessage();
            msg.From = "abc@cde.fgh";
            msg.To = "ryanturner03@gmail.com";
            msg.Subject = "Reminder: " + DateTime.Now.ToString();
            msg.Body = "This is a server generated message";
	
            SmtpMail.Send( msg );
        }
        catch( Exception x )
        {
            Debug.WriteLine( x );
        }
    }

    /// <summary>
    /// Test MSMQ
    /// </summary>
    private void DoSomeMSMQStuff()
    {
        using( MessageQueue queue = new MessageQueue(MSMQ_NAME) )
        {
            queue.Send(DateTime.Now);
            queue.Close();
        }
    }

    protected void Session_Start(Object sender, EventArgs e)
    {

    }

    protected void Application_BeginRequest(Object sender, EventArgs e)
    {
        // If the dummy page is hit, then it means we want to add another item
        // in cache
        if (HttpContext.Current.Request.Url.ToString() == DummyPageUrl)
        {
            // Add the item in cache and when succesful, do the work.
            RegisterCacheEntry();
        }
    }

    protected void Application_EndRequest(Object sender, EventArgs e)
    {

    }

    protected void Application_AuthenticateRequest(Object sender, EventArgs e)
    {

    }

    protected void Application_Error(Object sender, EventArgs e)
    {
        Debug.WriteLine(Server.GetLastError());
    }

    protected void Session_End(Object sender, EventArgs e)
    {

    }

    protected void Application_End(Object sender, EventArgs e)
    {

    }
       
</script>
